#include "catalog.h"
#include "query.h"
#include "index.h"

/*
 * Selects records from the specified relation.
 *
 * Returns:
 * 	OK on success
 * 	an error code otherwise
 */
Status Operators::Select(const string & result,      // name of the output relation
	                 const int projCnt,          // number of attributes in the projection
		         const attrInfo projNames[], // the list of projection attributes
		         const attrInfo *attr,       // attribute used inthe selection predicate 
		         const Operator op,         // predicate operation
		         const void *attrValue)     // literal value in the predicate
{

	//copy projNames attrInfo into a attrDesc in order to pass it to the other select funcs
	AttrDesc descProjNames[projCnt];
	AttrDesc descProj;
	int relnAttrCnt = 0;
	for(int x = 0; x < projCnt; x++)
	{
		Status descproj_status = attrCat->getInfo(projNames[x].relName, projNames[x].attrName, descProj);

		if(descproj_status != OK)
			return descproj_status;

		descProjNames[x] = descProj;
	}

	//First get the rec length
	//just to get rec len (the length of the record to be returned in the result)

	AttrDesc *resultDesc;
	int resultCnt;
	int rec_length = 0;
	Status result_info_status = attrCat->getRelInfo(result, resultCnt, resultDesc);
	if(result_info_status != OK)
		return result_info_status;

	for(int j = 0; j < resultCnt; j++)
	{
		rec_length += resultDesc[j].attrLen;
	}

	//This is a special case where the 'where clause' doesn't exist
	if(attr == NULL)
	{
		Status scan_select_status = 
			ScanSelect(result, projCnt, descProjNames, NULL, op, NULL, rec_length);
		
		return scan_select_status;

	}

	//Else we do the normal checks


	//This next section determines whether the where clause (attr) is indexed
	string relName = projNames[0].relName;

	AttrDesc *attrDesc;
	Status rel_info_status = attrCat->getRelInfo(relName, relnAttrCnt, attrDesc);
	if(rel_info_status != OK)
		return rel_info_status;

	bool indexed = false;
	int i = 0;
	for(i = 0; i < relnAttrCnt; i++)
	{
		if(strcmp(attrDesc[i].attrName, attr->attrName) == 0)
		{
			if(attrDesc[i].indexed == true)
			{
				indexed = true;
			}
			break;
		}
		else if(i == (relnAttrCnt - 1))
		{
			return ATTRNOTFOUND;
		}

	}

	if(op == EQ && indexed)
	{
		//use index select
		Status index_select_status = 
			IndexSelect(result, projCnt, descProjNames, &attrDesc[i], op, attrValue, rec_length);
		
		if(index_select_status != OK)
			return index_select_status;
	}
	else
	{
		//use scan select
		Status scan_select_status = 
			ScanSelect(result, projCnt, descProjNames, &attrDesc[i], op, attrValue, rec_length);

		if(scan_select_status != OK)
			return scan_select_status;
	}
	return OK;
}

